import type { FC, ReactNode } from 'react'
import React, { memo, useEffect, useRef, useState } from 'react'
import { PlusOutlined } from '@ant-design/icons'
import type { InputRef } from 'antd'
import { Input, Space, Tag, theme, Tooltip } from 'antd'

interface IProps {
  children?: ReactNode
  // 父组件通过该函数获取最新的tags数组
  updateTags?: (tags: string[]) => void
  tags: string[]
}

const InfoTags: FC<IProps> = (props) => {
  const { tags = [] } = props
  const { token } = theme.useToken()
  const [inputVisible, setInputVisible] = useState(false)
  const [inputValue, setInputValue] = useState('')
  const [editInputIndex, setEditInputIndex] = useState(-1)
  const [editInputValue, setEditInputValue] = useState('')
  const inputRef = useRef<InputRef>(null)
  const editInputRef = useRef<InputRef>(null)

  useEffect(() => {
    if (inputVisible) {
      inputRef.current?.focus()
    }
  }, [inputVisible])

  useEffect(() => {
    editInputRef.current?.focus()
  }, [inputValue])

  // 删除标签的回调
  const handleClose = (removedTag: string) => {
    const newTags = tags.filter((tag) => tag !== removedTag)
    props.updateTags?.(newTags)
  }

  // 设置输入框的状态
  const showInput = () => {
    setInputVisible(true)
  }

  // 输入框的内容发生改变触发的回调
  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setInputValue(e.target.value)
  }

  // 点击标签进入输入状态时：失去焦点或者按下回车就增加新标签
  const handleInputConfirm = () => {
    // 查重，只有没输入过的标签才被允许新增
    if (inputValue && tags.indexOf(inputValue) === -1) {
      const newTags = [...tags, inputValue]
      props.updateTags?.(newTags)
    }
    setInputVisible(false)
    setInputValue('')
  }

  // 监听输入框内容的改变
  const handleEditInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setEditInputValue(e.target.value)
  }

  // 编辑完成的回调
  const handleEditInputConfirm = () => {
    const newTags = [...tags]
    newTags[editInputIndex] = editInputValue
    props.updateTags?.(newTags)
    setEditInputIndex(-1)
    setInputValue('')
  }

  const tagInputStyle: React.CSSProperties = {
    width: 78,
    verticalAlign: 'top'
  }

  const tagPlusStyle: React.CSSProperties = {
    background: token.colorBgContainer,
    borderStyle: 'dashed'
  }

  // 渲染标签输入框和标签展示区域
  return (
    // 使用 Space 组件设置标签之间的间距，并将标签自动换行
    <Space size={[0, 8]} wrap>
      <Space size={[0, 8]} wrap>
        {/* 遍历 tags 数组，并返回对应的 JSX 元素 */}
        {tags.map((tag, index) => {
          // 如果正在编辑当前标签，则渲染输入框
          if (editInputIndex === index) {
            return (
              <Input
                ref={editInputRef}
                key={tag}
                size="small"
                style={tagInputStyle}
                value={editInputValue}
                onChange={handleEditInputChange}
                onBlur={handleEditInputConfirm}
                onPressEnter={handleEditInputConfirm}
              />
            )
          }
          // 否则，渲染标签组件
          const isLongTag = tag.length > 10 // 判断标签是否过长
          const tagElem = (
            <Tag
              key={tag}
              closable
              style={{ userSelect: 'none' }} // 禁止选择文本
              onClose={() => handleClose(tag)} // 关闭标签时的回调函数
            >
              <span
                onDoubleClick={(e) => {
                  if (index !== 0) {
                    setEditInputIndex(index)
                    setEditInputValue(tag)
                    // e.preventDefault() 是用来阻止默认事件发生的。在这里，它的作用是防止浏览器选中文字时触发双击事件，从而导致输入框无法正常显示。
                    e.preventDefault()
                  }
                }}
              >
                {/* 如果标签过长，则截取前五个字符并添加省略号 */}
                {isLongTag ? `${tag.slice(0, 10)}...` : tag}
              </span>
            </Tag>
          )
          // 如果标签过长，则使用 Tooltip 组件展示完整的标签文字
          return isLongTag ? (
            <Tooltip title={tag} key={tag}>
              {tagElem}
            </Tooltip>
          ) : (
            tagElem
          )
        })}
      </Space>
      {/* 如果正在输入新标签，则渲染输入框 */}
      {inputVisible ? (
        <Input
          ref={inputRef}
          type="text"
          size="small"
          style={tagInputStyle}
          value={inputValue}
          onChange={handleInputChange}
          onBlur={handleInputConfirm}
          onPressEnter={handleInputConfirm}
        />
      ) : (
        // 否则，渲染 "新增标签" 按钮
        <Tag style={tagPlusStyle} onClick={showInput}>
          <PlusOutlined /> 新增标签
        </Tag>
      )}
    </Space>
  )
}

export default memo(InfoTags)
